#include <stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>

#define BUF_LEN 8

int main() {
    libusb_device **devs = NULL;
    libusb_context *ctx = NULL;
    int ret = 0;
    int count = 0;
    int interface_num = 0;
    int inter_in_endpoint = 0;
    int find_flag = 0;
    struct libusb_device_descriptor desc = {0};
    libusb_device *device = NULL;
    struct libusb_config_descriptor *config_desc = NULL;
    struct libusb_interface_descriptor *intf_desc = NULL;
    libusb_device_handle *dev_handle = NULL;
    unsigned char buffer[BUF_LEN] = {0};
    int transferred = 0;

    // libusb初始化
    ret = libusb_init(&ctx);
    if (ret < 0) {
        fprintf(stderr, "Error initializing libusb: %s\n", libusb_strerror(ret));
        return 1;
    }

    // 获取usb的列表,返回usb的个数
    count = libusb_get_device_list(ctx, &devs);
    if (count < 0) {
        fprintf(stderr, "Error getting device list: %s\n", libusb_strerror(count));
        libusb_exit(ctx);
        return 1;
    }

    printf("Number of USB devices: %d\n", count);

    for (int i = 0; i < count; i++) {
        device = devs[i];

        // 获取USB设备描述符
        ret = libusb_get_device_descriptor(device, &desc);
        if (ret < 0) {
            fprintf(stderr, "Error getting device descriptor %d %s\n", i, libusb_strerror(ret));
            continue;
        }
        printf("Vendor ID: 0x%04x, Product ID: 0x%04x\n", desc.idVendor, desc.idProduct);
        printf("NumConfigurations: 0x%02x\n", desc.bNumConfigurations);
    }

    for (int i = 0; i < count; i++) {
        device = devs[i];

        // 获取USB的配置描述符,第一次插入时候默认使用配置0
        ret = libusb_get_config_descriptor(device, 0, &config_desc);
        if (ret) {
            fprintf(stderr, "Error getting device config descriptor %s\n", libusb_strerror(ret));
            libusb_exit(ctx);
            return 1;
        }

        // 获取接口描述符
        for (int interface = 0; interface < config_desc->bNumInterfaces; interface++) {
            // 获取USB的配置描述符描述符,第一次插入时候默认使用配置0中的接口0
            intf_desc = &config_desc->interface[interface].altsetting[0];
            // 获取接口描述符中的个数
            interface_num = intf_desc->bInterfaceNumber;

            // 通过接口描述符,判断是否是鼠标
            /**
             * bInterfaceClass         3 Human Interface Device
             * bInterfaceSubClass      1 Boot Interface Subclass
             * bInterfaceProtocol      2 Mouse
            */
            if (intf_desc->bInterfaceClass != 3 || intf_desc->bInterfaceProtocol != 2) {
                // 继续查找鼠标
                continue;
            } else {
                // 找到鼠标
                printf("Find Usb Mouse\n");
                /**
                 * 查找USB端点
                 * 端点 1: 用于从主机PC接收的命令的Bulk Out端点
                 * 端点 2: 用于发送给主机PC的响应的Bulk In端点
                */
                /**
                 *  Endpoint Descriptor:
                 *    bLength                 7
                 *    bDescriptorType         5
                 *    bEndpointAddress     0x81  EP 1 IN
                 *    bmAttributes            3
                 *    Transfer Type            Interrupt
                 *    Synch Type               None
                 *    Usage Type               Data
                 *    wMaxPacketSize     0x0008  1x 8 bytes
                 *    bInterval               1
                */
                for (int i = 0; i < intf_desc->bNumEndpoints; i++) {
                    // 判断端点描述符的bmAttributes和bEndpointAddress
                    if ((intf_desc->endpoint[i].bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT ||
                        (intf_desc->endpoint[i].bEndpointAddress & LIBUSB_ENDPOINT_IN) == LIBUSB_ENDPOINT_IN) {
                        //找到inter输入端点
                        inter_in_endpoint = intf_desc->endpoint[i].bEndpointAddress;
                        find_flag = 1;
                        break;
                    }
                }  
            }

            // 找到鼠标的端点
            if (find_flag) {
                break;
            }
        }
        // 释放USB的配置描述符
        libusb_free_config_descriptor(config_desc);

        if (find_flag) {
            break;
        }
    }

    // 没有找到USB鼠标
    if (!find_flag) {
        //释放USB列表
        libusb_free_device_list(devs, 1);
        //释放libusb
        libusb_exit(ctx);
        return 1;
    }

    // 通过libusb_device device打开设备
    ret = libusb_open(device, &dev_handle);
    if (ret) {
        fprintf(stderr, "Error libusb open devices %s\n", libusb_strerror(ret));
        libusb_free_device_list(devs, 1);
        libusb_exit(ctx);
        return 1;
    }

    //释放USB列表
    libusb_free_device_list(devs, 1);

    // 使用libusb访问USB设备时,需要先移除(detach)设备原来的驱动程序,
    // 然后认领接口(claim interface)
    // 只是设置一个标记位表示libusb_claim_interface
    // 使用libusb_claim_interface时会detach原来的驱动
    libusb_set_auto_detach_kernel_driver(dev_handle, 1);  

    // 标记这个interface已经被使用认领了
    ret = libusb_claim_interface(dev_handle, interface_num);
    if (ret) {
        fprintf(stderr, "Error libusb_claim_interface %s\n", libusb_strerror(ret));
        libusb_exit(ctx);
        return 1;
    }

    // 获取usb鼠标的数据
    // 等待5000ms
    // 0阻塞等待
    while (1) {
        ret = libusb_interrupt_transfer(dev_handle, inter_in_endpoint,\
            buffer, sizeof(buffer), &transferred, 5000);
        if (!ret) {
            // 解析数据
            // transferred实际返回的数据长度
            for (int i = 0; i < transferred; i++) {
                printf("%02x ", buffer[i]);
            }
            printf("\n");
        } else if (ret == LIBUSB_ERROR_TIMEOUT) {
            fprintf(stderr, "libusb_interrupt_transfer timout\n");
        } else {
            fprintf(stderr, "libusb_interrupt_transfer err : %d\n", ret);
        }
    }

    /* libusb_close */
    libusb_release_interface(dev_handle, interface_num);
    // 关闭dev_handle
    libusb_close(dev_handle);
    //释放libusb
    libusb_exit(ctx);

    return 0;
}
